package fr.cephb.joperon.core;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.OperationStatus;
import com.sleepycat.db.Transaction;

import fr.cephb.berkeley.ByteReader;
import fr.cephb.berkeley.ByteWriter;
import fr.cephb.berkeley.DBUtils;
import fr.cephb.lang.UInt32;


/**
 * A database containing no duplicate key
 *
 * @param <K> the key
 * @param <V> the value
 */
public abstract class OperonDBSingleValue<K extends Comparable<K>,V>
	extends OperonDB<K,V> {

	protected OperonDBSingleValue(Operon operon) {
		super(operon);
		}
	
	/** return a map of Key/value from a given set of key */
	public Map<K,V> get(Set<K> keys)  throws DatabaseException
		{
		Map<K,V> map= new HashMap<K, V>();
		for(K key:keys)
			{
			V value= get(key);
			if(value!=null) map.put(key, value);
			}
		return map;
		}
	
	/** return the value for the given key */
	public V get(K key) throws DatabaseException
		{
		DatabaseEntry ek = keyToEntry(key);
		DatabaseEntry ev= get(ek);
		return ev==null?null:readValue(ek, ev);
		}
	
	/*
	public List<V> getArrayOf(K key)  throws DatabaseException
		{
		DatabaseEntry ek = keyToEntry(key);
		DatabaseEntry ev= get(ek);
		
		
		}*/
	
	
	/** return false */
	public  boolean isAllowingDuplicates()
		{
		return false;
		}
	
	/** put a new key/value in this database */
	public final OperationStatus put(K key,V value) throws DatabaseException
		{
		return put(null,key,value);
		}
	
	/** put a new key/value in this database with a Transaction */
	public OperationStatus put(Transaction tx,K key,V value) throws DatabaseException
		{
		DatabaseEntry ek = keyToEntry(key);
		DatabaseEntry ev = valueToEntry(value);
		return getDatabase().put(tx, ek, ev);
		}
	
	/** A specialized OperonDBSingleValue for java.lang.String as a Key */
	public static abstract class STRING<V>
	extends OperonDBSingleValue<String, V>
		{
		public STRING(Operon operon)
			{
			super(operon);
			}
		
		@Override
		public String keyFromString(String s) {
			return s;
			}
		
		@Override
		protected DatabaseEntry keyToEntry(String key) throws DatabaseException {
			return new DatabaseEntry(DBUtils.string2CString(key));
			}
		@Override
		public String readKey(DatabaseEntry key, DatabaseEntry data)
				throws DatabaseException {
			return new ByteReader(key).readCString();
			}
		}
	
	/** A specialized OperonDBSingleValue for java.lang.String as a Key but <b>Case Insensitive</b>
	 * (convert to lowerCase )*/
	public static abstract class ISTRING<V>
		extends STRING<V>
		{
		public ISTRING(Operon operon)
			{
			super(operon);
			}
		
		@Override
		/** convert to lowerCase */
		public String keyFromString(String s)
			{
			s=super.keyFromString(s);
			return s==null?null:s.toLowerCase();
			}
		@Override
		protected DatabaseEntry keyToEntry(String s)
				throws DatabaseException {
			return super.keyToEntry(s.toLowerCase());
			}
		@Override
		public String readKey(DatabaseEntry key, DatabaseEntry data)
				throws DatabaseException {
			return super.readKey(key, data).toLowerCase();
			}
		}

	/** A specialized OperonDBSingleValue for java.lang.Integer as a Key */
	public static abstract class INTEGER<V>
	extends OperonDBSingleValue<Integer, V>
		{
		public INTEGER(Operon operon)
			{
			super(operon);
			}
		
		@Override
		public Integer keyFromString(String s) {
			return new Integer(s);
			}
		
		@Override
		protected DatabaseEntry keyToEntry(Integer key) throws DatabaseException
			{
			ByteWriter w= new ByteWriter();
			w.writeInt32(key);
			return w.getEntry();
			}
		
		@Override
		public Integer readKey(DatabaseEntry key, DatabaseEntry data)
				throws DatabaseException {
			return new ByteReader(key).readInt32();
			}
		}

	/** A specialized OperonDBSingleValue for java.lang.Long as a Key */
	public static abstract class LONG<V>
	extends OperonDBSingleValue<Long, V>
		{
		public LONG(Operon operon)
			{
			super(operon);
			}
		
		@Override
		public Long keyFromString(String s) {
			return new Long(s);
			}
		
		@Override
		protected DatabaseEntry keyToEntry(Long key) throws DatabaseException {
			ByteWriter w= new ByteWriter();
			w.writeInt64(key);
			return w.getEntry();
			}
		@Override
		public Long readKey(DatabaseEntry key, DatabaseEntry data)
				throws DatabaseException {
			return new ByteReader(key).readInt64();
			}

		}
	
	/** Specific implementation  using UINT32 as a key */
	public static abstract class UINT32<V>
	extends OperonDBSingleValue<fr.cephb.lang.UInt32,V>
		{
		public UINT32(Operon operon)
			{
			super(operon);
			}
		

		public V get(long uint32) throws DatabaseException
			{
			return get(new UInt32(uint32));
			}
		
		
		public KeyValueIterator listKeyValues(long start,long end, boolean includeEnd) throws DatabaseException
			{
			return listKeyValues(new UInt32(start),new UInt32(end),includeEnd);
			}
		
	
		
		
		@Override
		public fr.cephb.lang.UInt32 keyFromString(String s) {
			return new fr.cephb.lang.UInt32(s);
			}
		
		@Override
		protected DatabaseEntry keyToEntry(UInt32 key) throws DatabaseException {
			return new DatabaseEntry(new ByteWriter().writeUInt32(key).getBytes());
			}
		@Override
		public UInt32 readKey(DatabaseEntry key, DatabaseEntry data)
				throws DatabaseException {
			UInt32 k= new UInt32(new ByteReader(key).readUInt32());
			return k;
			}
		}
	
	
}
